/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.lcm.metadata.common;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.lcm.metadata.api.AbstractMetadataContent;
import com.inspur.edp.lcm.metadata.api.IMdExtRuleContent;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataDto;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.common.configuration.MdExtRuleSerializerHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataSerializerHelper;
import com.inspur.edp.lcm.metadata.common.configuration.TransferSerializerHelper;
import com.inspur.edp.lcm.metadata.spi.MdExtendRuleSerializer;
import com.inspur.edp.lcm.metadata.spi.MetadataContentSerializer;
import com.inspur.edp.lcm.metadata.spi.MetadataTransferSerializer;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmConfigResolveException;
import com.inspur.edp.metadata.rtcustomization.api.exception.ErrorCodes;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmParseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;

/**
 * Classname MetadataDtoConverter
 * Description 元数据转换器
 * Date 2019/11/14 20:02
 *
 * @author zhongchq
 * @version 1.0
 */
@Slf4j
public class MetadataDtoConverter {

    public static MetadataDto asDto(GspMetadata metadata) {
        if (metadata == null) {
            return null;
        }
        MetadataDto metadataDto = new MetadataDto();
        metadataDto.setBizobjectID(metadata.getHeader().getBizobjectID());
        metadataDto.setType(metadata.getHeader().getType());
        metadataDto.setId(metadata.getHeader().getId());
        metadataDto.setCode(metadata.getHeader().getCode());
        metadataDto.setName(metadata.getHeader().getName());
        metadataDto.setNameSpace(metadata.getHeader().getNameSpace());
        metadataDto.setFileName(metadata.getHeader().getFileName());
        metadataDto.setLanguage(metadata.getHeader().getLanguage());
        metadataDto.setNameLanguage(metadata.getHeader().getNameLanguage());
        metadataDto.setRelativePath(metadata.getRelativePath());
        //GspMetadata没有此属性
        metadataDto.setIsTranslating(metadata.getHeader().isTranslating());
        metadataDto.setExtendProperty(metadata.getExtendProperty());
        metadataDto.setExtendable(metadata.getHeader().isExtendable());
        metadataDto.setExtented(metadata.isExtended());
        metadataDto.setPreviousVersion(metadata.getPreviousVersion());
        metadataDto.setVersion(metadata.getVersion());
        metadataDto.setProperties(metadata.getProperties());
        String ref = "";
        ObjectMapper objectMapper = ServiceUtils.getMapper();
        if (metadata.getRefs() != null && metadata.getRefs().size() > 0) {
            try {
                metadataDto.setRefs(objectMapper.writeValueAsString(metadata.getRefs()));

            } catch (JsonProcessingException e) {
                log.error("序列化元数据依赖关系失败", e);
            }

        }
        if (metadata.getContent() != null) {

            String transferStr = null;
            JsonNode jsonNode;
            MetadataTransferSerializer transferSerializer = TransferSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
            if( !ObjectUtils.isEmpty(transferSerializer)){
                transferStr = transferSerializer.serialize(metadata.getContent());
            }
            else {
                MetadataContentSerializer metadataContentSerializer = MetadataSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
                if (metadataContentSerializer == null) {
                    throw new LcmConfigResolveException(ErrorCodes.ECP_CONFIG_RESOLVE_0006, metadata.getHeader().getType());
                }
                jsonNode = metadataContentSerializer.Serialize(metadata.getContent());

                try {
                    transferStr = objectMapper.writeValueAsString(jsonNode);
                } catch (JsonProcessingException e) {
                    log.error("反序列化元数据内容节点失败", e);
                }
            }

            metadataDto.setContent(transferStr);
        }
        if (metadata.getExtendRule() != null) {
            MdExtendRuleSerializer serializer = MdExtRuleSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
            if (serializer != null) {
                JsonNode jsonNode = serializer.serialize(metadata.getExtendRule());

                String transferStr = null;
                try {
                    transferStr = objectMapper.writeValueAsString(jsonNode);
                } catch (JsonProcessingException e) {
                    log.error("序列化元数据扩展规则失败", e);
                }
                metadataDto.setExtendRule(transferStr);
            }
        }

        return metadataDto;
    }

    public static GspMetadata asMetadata(MetadataDto metadataDto) {
        if (metadataDto == null) {
            return null;
        }
        GspMetadata metadata = new GspMetadata();
        metadata.setHeader(new MetadataHeader());
        metadata.getHeader().setId(metadataDto.getId());
        metadata.getHeader().setBizobjectID(metadataDto.getBizobjectID());
        metadata.getHeader().setNameSpace(metadataDto.getNameSpace());
        metadata.getHeader().setType(metadataDto.getType());
        metadata.getHeader().setFileName(metadataDto.getFileName());
        metadata.setRelativePath(metadataDto.getRelativePath());
        metadata.getHeader().setLanguage(metadataDto.getLanguage());
        metadata.getHeader().setTranslating(metadataDto.isTranslating);
        metadata.setExtendProperty(metadataDto.getExtendProperty());
        metadata.getHeader().setExtendable(metadataDto.isExtendable());
        metadata.setExtended(metadataDto.isExtented());
        metadata.setPreviousVersion(metadataDto.getPreviousVersion());
        metadata.setVersion(metadataDto.getVersion());
        metadata.getHeader().setNameLanguage(metadataDto.getNameLanguage());
        metadata.setProperties(metadataDto.getProperties());
        ObjectMapper objectMapper = ServiceUtils.getMapper();
        if (metadataDto.getRefs() != null && metadataDto.getRefs() != "") {
            try {
                metadata.setRefs(objectMapper.readValue(metadataDto.getRefs(), new TypeReference<ArrayList<MetadataReference>>() {
                }));
            } catch (JsonProcessingException e) {
                log.error("序列化元数据依赖关系失败", e);
            }
        } else {
            metadata.setRefs(new ArrayList<>());
        }

        IMetadataContent content=null;
        if (metadataDto.getContent() != null) {
            MetadataTransferSerializer transferSerializer = TransferSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
            if( !ObjectUtils.isEmpty(transferSerializer)){
                content = transferSerializer.deserialize(metadataDto.getContent());
            }
            else {
                //反序列化
                MetadataContentSerializer metadataContentSerializer = MetadataSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
                if (metadataContentSerializer == null) {
                    throw new LcmConfigResolveException(ErrorCodes.ECP_CONFIG_RESOLVE_0006, metadata.getHeader().getType());
                }

                JsonNode contentObj;
                try {
                    contentObj = objectMapper.readTree(metadataDto.getContent());
                } catch (Exception e) {
                    throw new LcmParseException(e, ErrorCodes.ECP_PARSE_0002, metadataDto.getId());
                }

                content = metadataContentSerializer.DeSerialize(contentObj);
            }

            metadata.setContent(content);
        }
        if (metadataDto.getExtendRule() != null) {
            MdExtendRuleSerializer serializer = MdExtRuleSerializerHelper.getInstance().getManager(metadata.getHeader().getType());
            if (serializer != null) {
                JsonNode contentObj;
                try {
                    contentObj = objectMapper.readTree(metadataDto.getContent());
                } catch (Exception e) {
                    throw new LcmParseException(e, ErrorCodes.ECP_PARSE_0002, metadataDto.getId());
                }

                IMdExtRuleContent extRule = serializer.deSerialize(contentObj);
                metadata.setExtendRule(extRule);
            }
        }

        AbstractMetadataContent abstractMetadataContent = null;
        
        try {
            abstractMetadataContent = (AbstractMetadataContent) metadata.getContent();
        } catch (RuntimeException e) {}
        
        if (abstractMetadataContent != null) {
            metadata.getHeader().setCode(abstractMetadataContent.getCode() == null ? metadataDto.getCode() : abstractMetadataContent.getCode());
            metadata.getHeader().setName(abstractMetadataContent.getName() == null ? metadataDto.getName() : abstractMetadataContent.getName());
        } else {
            metadata.getHeader().setCode(metadataDto.getCode());
            metadata.getHeader().setName(metadataDto.getName());
        }

        return metadata;
    }
}
